package com.globalwave.common.service;


import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.Types;
import java.util.ArrayList;
import java.util.List;

import org.dom4j.DocumentHelper;
import org.dom4j.Element;

import com.globalwave.base.BaseServiceImpl;
import com.globalwave.common.ArrayOrderList;
import com.globalwave.common.ArrayPageList;
import com.globalwave.common.C;
import com.globalwave.common.Convertor;
import com.globalwave.common.GenCode;
import com.globalwave.common.cache.CodeHelper;
import com.globalwave.common.db.ConnectionProvider;
import com.globalwave.common.entity.Field;
import com.globalwave.common.entity.View;
import com.globalwave.common.entity.ViewCriterion;
import com.globalwave.common.entity.VirtualEditForm;
import com.globalwave.common.entity.VirtualGrid;
import com.globalwave.common.entity.VirtualSearchForm;
import com.globalwave.common.exception.BusinessException;

public class ViewServiceImpl 
       extends BaseServiceImpl 
       implements ViewService {

	private FieldService fieldService ;
	
    public VirtualGrid create(String viewAsXML, boolean isGenCode) throws Exception {
    	VirtualGrid result = new VirtualGrid() ;
    	
    	Element element = DocumentHelper.parseText(viewAsXML).getRootElement() ;

    	View gridView = (View)Convertor.xml2Object(element.element("grid").element("view"), View.class) ;

    	if (getByCode(gridView.getCode_()) != null) {
    		// E0101010003', '没有找到视图配置！
    		throw new BusinessException("E0101010003") ;
    		//e.setCode("view code exist") ;
    	}
    		
    	List<Object> list = Convertor.xml2List(element.element("editForm").element("fields"), Field.class) ;    	
    	if (list != null && list.size() != 0) {
    		View view = (View)Convertor.xml2Object(element.element("editForm").element("view"), View.class) ;    

        	view.setType_(View.TYPE_EDIT_FORM) ;
        	view.setCode_(gridView.getCode_()) ;
        	view.setName_(gridView.getName_()) ;
        	view.setIndex_(gridView.getIndex_()) ;
    		
    		view = (View)jdbcDao.insert(view) ;
    		
    		gridView.setEdit_view_id(view.getView_id()) ;
    		
	    	createFields(list, view.getView_id()) ;

    		result.setEditForm(new VirtualEditForm()) ;
    		result.getEditForm().setView(view) ;
    		result.getEditForm().addFields(list);
    	}
    	
    	list = Convertor.xml2List(element.element("searchForm").element("fields"), Field.class) ;
    	if (list != null && list.size() != 0) {
    		View view = (View)Convertor.xml2Object(element.element("searchForm").element("view"), View.class) ;

    		view.setType_(View.TYPE_SEARCH_FORM) ;
        	view.setCode_(gridView.getCode_()) ;
        	view.setName_(gridView.getName_()) ;
        	view.setIndex_(gridView.getIndex_()) ;
        	
    		view = (View)jdbcDao.insert(view) ;
    		
    		gridView.setSearch_view_id(view.getView_id()) ;
    		
	    	createFields(list, view.getView_id()) ;

    		result.setSearchForm(new VirtualSearchForm()) ;
    		result.getSearchForm().setView(view) ;
    		result.getSearchForm().addFields(list);
    	}
    	
    	gridView.setType_(View.TYPE_GRID) ;
    	
    	gridView = (View)jdbcDao.insert(gridView) ;
    	
    	//final Long result = gridView.getView_id() ;
    	
    	list = Convertor.xml2List(element.element("grid").element("fields"), Field.class) ;
    	createFields(list, gridView.getView_id()) ;

		result.setView(gridView) ;
		result.addFields(list);
		
		if (isGenCode) {
		    new GenCode(result).generate() ;
		}
    	return result ;
    }

    public void update(String viewAsXML, boolean isGenCode) throws Exception {
    	
    	Element element = DocumentHelper.parseText(viewAsXML).getRootElement() ;

    	View gridView = (View)Convertor.xml2Object(element.element("grid").element("view"), View.class) ;
    	gridView.addExclusions("type_") ;
    	gridView.addExclusions("code_");
    		
    	List<Object> list = Convertor.xml2List(element.element("editForm").element("fields"), Field.class) ;    	
    	if (list != null && list.size() != 0) {
    		View view = (View)Convertor.xml2Object(element.element("editForm").element("view"), View.class) ;    

        	view.setName_(gridView.getName_()) ;
        	view.setIndex_(gridView.getIndex_()) ;
        	
        	if (view.getView_id()!=null){
        		view.addExclusions("type_") ;
        		view.addExclusions("code_") ;
    		    jdbcDao.update(view) ;
        		fieldService.deleteByViewId(view.getView_id()) ;
        	} else {
        		view.setType_(View.TYPE_EDIT_FORM) ;
            	view.setCode_(gridView.getCode_()) ;
            	view = (View)jdbcDao.insert(view) ;
            	gridView.setEdit_view_id(view.getView_id()) ;
        	}
        	
    		createFields(list, view.getView_id()) ;
    	}
    	
    	list = Convertor.xml2List(element.element("searchForm").element("fields"), Field.class) ;
    	if (list != null && list.size() != 0) {
    		View view = (View)Convertor.xml2Object(element.element("searchForm").element("view"), View.class) ;

        	view.setName_(gridView.getName_()) ;
        	view.setIndex_(gridView.getIndex_()) ;

        	if (view.getView_id()!=null){
            	view.addExclusions("type_") ;
            	view.addExclusions("code_") ;
    		    jdbcDao.update(view) ;
        		fieldService.deleteByViewId(view.getView_id()) ;
        	} else {
        		view.setType_(View.TYPE_SEARCH_FORM) ;
            	view.setCode_(gridView.getCode_()) ;
            	view = (View)jdbcDao.insert(view) ;
            	gridView.setSearch_view_id(view.getView_id()) ;
        	}

    		createFields(list, view.getView_id()) ;
    	}
    	
    	jdbcDao.update(gridView) ;

		fieldService.deleteByViewId(gridView.getView_id()) ;
		list = Convertor.xml2List(element.element("grid").element("fields"), Field.class) ;
    	createFields(list, gridView.getView_id()) ;

		if (isGenCode) {
    	    new GenCode(getUIMetaData(gridView.getView_id(), null)).generate() ;
		}
    }

 
    private void createFields(final List<Object> list, final Long viewId) throws Exception {
    	int i = 1 ; 
    	for(Object element:list) {
    		Field f = (Field) element ;
    		f.setField_id(null) ;
    		f.setView_id(viewId) ;
    		f.setIndex_(i++) ;
    		jdbcDao.insert(f) ;
    	}
    }
 
    
    public View create(View view) throws Exception {
    	
    	final View result = (View) jdbcDao.insert(view, true);
    	
    	return result ;
    }

    public void update(View view) throws Exception {
        jdbcDao.update(view) ;
    }

    public void delete(View view) throws Exception {
        
        jdbcDao.delete(view) ;
        
    }

    public void deleteAll(Long[] ids) throws Exception {
    	/*
    	ViewCriterion criterion = new ViewCriterion() ;
        criterion.setIds(ids) ;
        jdbcDao.delete(View.class, criterion) ;
        */
    	
    	List<Long> viewIdList = new ArrayList<Long>(3) ;
    	for (Long id:ids) {
            View view = (View)this.get(id);
            if (view == null) {
            	//BusinessException e = new BusinessException() ;
            	//e.setCode("can't not find view") ;
        		// E0101010003', '没有找到视图配置！
        		throw new BusinessException("E0101010003") ;
            }
            viewIdList.add(view.getView_id());
            viewIdList.add(view.getEdit_view_id());
            viewIdList.add(view.getSearch_view_id()) ;
    	}
    	
        Long[] viewIds = viewIdList.toArray(new Long[]{}) ;
        fieldService.deleteByViewIds(viewIds) ;

    	ViewCriterion criterion = new ViewCriterion() ;
        criterion.setIds(viewIds) ;
        jdbcDao.delete(View.class, criterion) ;
    }

    public ArrayPageList<View> query(
    		ViewCriterion viewCriterion, 
            int pageIndex, 
            int pageSize, 
            ArrayOrderList orderList) throws Exception {
        
        if (orderList == null) {
            orderList = new ArrayOrderList() ;
            orderList.addAsc("index_") ;
        }
        
        return (ArrayPageList<View>)jdbcDao.query(viewCriterion, pageIndex, pageSize, orderList, View.class);
    }

	@Override
	public View get(Long viewId) throws Exception {
        
    	ViewCriterion viewCriterion = new ViewCriterion();
    	viewCriterion.setView_id(viewId) ;
    	ArrayPageList<View> views = query(viewCriterion, -2, -1, null) ;
    	if (views.size() > 0) {
    		return views.get(0) ;
    	}
		return null;
	}

	public View get(String viewCode) throws Exception {
        
    	ViewCriterion viewCriterion = new ViewCriterion();
    	viewCriterion.setCode_(viewCode) ;
    	viewCriterion.setType_(View.TYPE_GRID) ;
    	ArrayPageList<View> views = query(viewCriterion, -2, -1, null) ;
    	if (views.size() > 0) {
    		return views.get(0) ;
    	}
		return null;
	}


	public View get(String viewCode, String type) throws Exception {
        
    	ViewCriterion viewCriterion = new ViewCriterion();
    	viewCriterion.setCode_(viewCode) ;
    	viewCriterion.setType_(type) ;
    	ArrayPageList<View> views = query(viewCriterion, -2, -1, null) ;
    	if (views.size() > 0) {
    		return views.get(0) ;
    	}
		return null;
	}
	public View getByCode(String code) throws Exception {
        
    	View viewCriterion = new View();
    	viewCriterion.setCode_(code) ;
    	ArrayPageList<View> views = (ArrayPageList<View>)jdbcDao.query(viewCriterion, -2, -1, null, View.class) ;
    	if (views.size() > 0) {
    		return views.get(0) ;
    	}
		return null;
	}

    public List<Field> getFieldsBySql(String sql) throws Exception {
    	ResultSetMetaData metaData = jdbcDao.getMetaData(sql) ;

    	int len = metaData.getColumnCount() ;
    	List<Field> result = new ArrayList<Field>(len) ;
    	
    	for (int i = 1 ; i <= len ; i ++) {
    		Field field = new Field() ;    		
    		result.add(field) ;
    		
    		field.setIndex_(i) ;
    		field.setCode_(metaData.getColumnName(i).toLowerCase()) ;
    		field.setName_(metaData.getColumnLabel(i)) ;
    		field.setType_(metaData.getColumnType(i)) ;
    		
    		if (Types.NUMERIC == field.getType_()) {
    			if (metaData.getScale(i) == 0) {
    				field.setType_(Types.BIGINT) ;
    			} else {
    				field.setType_(Types.DOUBLE) ;
    			}
    		} else if (Types.CHAR == field.getType_()) {
    			field.setType_(Types.VARCHAR) ;
    		}
    		
    		field.setIs_nullable(
    				metaData.isNullable(i) == ResultSetMetaData.columnNullable?
    						C.TRUE_INTEGER : C.FALSE_INTEGER) ;
    		
    		field.setIs_primary_key(C.FALSE_INTEGER) ;
    	}
    	
    	return result ;
    }

    public List<View> getTables(String dbName) throws Exception {
    	List<View> result = new ArrayList<View>() ;
        String[] types = { "TABLE" };
        ConnectionProvider connectionProvider = null ;
        try {
        	connectionProvider = new ConnectionProvider() ;
	        ResultSet resultSet = 
	        	connectionProvider.getConnection(dbName).getMetaData().getTables(null, null, "%", types);
	
	        while (resultSet.next()) {
	            String tableName = resultSet.getString(3);
	            //String tableCatalog = resultSet.getString(1);
	            String tableSchema = resultSet.getString(2);
	          
	            View view = new View() ;
	            view.setTable_name(tableSchema + "." + tableName) ;
	          
	            result.add(view) ;
	        }
        } finally {
        	connectionProvider.closeAllConnection() ;
        }
    	 
        
        return result ;
    	
    }
    /*
    public void generateCodebyTableName(final int dbtype, final String tableName, final String projectName) throws Exception {
    	List<Field> fields = this.getFieldsBySql(SqlUtils.getUnlockRead(dbtype, "select * from " + tableName)) ;
    	for (Field f:fields) {
    		
    	}
    }*/
    

    public VirtualGrid getUIMetaData(Long viewId, String viewCode) throws Exception {
    	
    	final VirtualGrid result = new VirtualGrid() ;
    	
    	// grid
    	View view = (viewId != null?this.get(viewId):this.get(viewCode)) ;
    	
    	if (view == null) {
    		//final BusinessException e = new BusinessException() ;
    		//e.setCode("view not Found!") ;
    		// E0101010003', '没有找到视图配置！
    		throw new BusinessException("E0101010003") ;
    	}
    	result.setView(view) ;

    	if (viewId == null) {
    		viewId = view.getView_id() ;
    	}
    	
    	ArrayPageList<Field> fields = fieldService.queryByViewId(viewId) ;

    	if (fields.size() > 0) {        	
        	result.setFields(fields) ;
        	setOptions(fields) ;
    	}

    	Long editViewId = view.getEdit_view_id() ;
    	Long searchViewId = view.getSearch_view_id();
    	
        /// edit form 
    	if (editViewId != null) {
	    	view = this.get(editViewId) ;
	    	
	    	if (view != null) {
	    		VirtualEditForm editForm = new VirtualEditForm() ;
	    		result.setEditForm(editForm) ;
	    		
	            editForm.setView(view) ;
	
	        	fields = fieldService.queryByViewId(editViewId) ;
	
	        	if (fields.size() > 0) {
	        		editForm.setFields(fields) ;
	        		setOptions(fields) ;
	        		
	        		if (result.getFields() == null) {// 如果查询时，没有配置字段，从edit form中取得配置
	        			List<Field> fieldsCopy = new ArrayList<Field>() ;
	        			result.setFields(fieldsCopy) ;
	        			
	        			for (Field f:fields) {
	        				Field fieldCopy = new Field() ;
	        				fieldCopy.setCode_(f.getCode_()) ;
	        				fieldCopy.setName_(f.getName_()) ;
	        				fieldsCopy.add(fieldCopy) ;
	        			}
	        		}
	        	}
	    	}
    	}

        /// search form 
    	if (searchViewId != null) {
	    	view = this.get(searchViewId) ;
	    	
	    	if (view != null) {
	    		VirtualSearchForm searchForm = new VirtualSearchForm() ;
	    		result.setSearchForm(searchForm) ;
	    		
	            searchForm.setView(view) ;
	
	        	fields = fieldService.queryByViewId(searchViewId) ;
	
	        	if (fields.size() > 0) {
	        		searchForm.setFields(fields) ;
	        		setOptions(fields) ;
	        	}
	    	}
    	}
    	return result ;
    }

    public VirtualEditForm getEditFormMetaData(String viewCode) throws Exception {
    	
    	VirtualEditForm result = new VirtualEditForm() ;
    	// grid
    	View view = this.get(viewCode, View.TYPE_ATTRIBUTE_FORM) ;
    	
    	if (view == null) {
    		//final BusinessException e = new BusinessException() ;
    		//e.setCode("view not Found!") ;
    		// E0101010003', '没有找到视图配置！
    		throw new BusinessException("E0101010003") ;
    	}
    	result.setView(view) ;
    	
    	ArrayPageList<Field> fields = fieldService.queryByViewId(view.getView_id()) ;

    	if (fields.size() > 0) {        	
        	result.setFields(fields) ;
        	setOptions(fields) ;
    	}

    	return result ;
    }
    
    private void setOptions(List<Field> fields) {
    	for (Field field:fields) {
    		if (Field.INPUT_TYPE_COMBOBOX.equals(field.getInput_type())
    				|| Field.INPUT_TYPE_RADIO.equals(field.getInput_type())) {
    			String[] optionParams = field.getInput_params().split(":") ;
    			try {
    		        field.setOptions(CodeHelper.getMap(optionParams[0], optionParams[1])) ;
    			} catch (Exception e) {
    				logger.error(e.getMessage(), e) ;
    			}
    		}
    	}
    }

	public void setFieldService(FieldService fieldService) {
		this.fieldService = fieldService;
	}
    
}
